package smashedapples.forms
{
	import com.google.maps.interfaces.IControl;

	import mx.containers.Form;
	import mx.core.Container;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	import mx.events.ValidationResultEvent;
	import mx.validators.Validator;

	import smashedapples.events.FormEvent;
	import smashedapples.utils.ObjectUtils;


	[Event( name="reset",type="smashedapples.events.FormEvent" )]
	[Event( name="submit",type="smashedapples.events.FormEvent" )]
	[Event( name="cancel",type="smashedapples.events.FormEvent" )]

	public class Form extends mx.containers.Form
	{



		public function Form()
		{
			super();
			this.percentHeight = 100;
			this.percentWidth = 100;
			this.addEventListener( FlexEvent.SHOW, handleShowEvent );
			this.addEventListener( FlexEvent.CREATION_COMPLETE, handleCreationComplete );
		}


		/**
		 *  comma delimited list that represents data objects that don't show up on the screen, but that
		 *  we want to keep track of anyways, for example primary keys`
		 */
		public var hidden:String = "";

		/**
		 * @private internal variable to keep track of hidden values
		 */
		private var hiddenValues:Object = {};

		public var defaultFocusField:String;


		protected function handleCreationComplete( event:FlexEvent ):void
		{
			this.setDefaultFocusField();
		}

		protected function handleShowEvent( event:FlexEvent ):void
		{
			this.setDefaultFocusField();
		}

		protected function setDefaultFocusField():void
		{
			var control:UIComponent;

			if( this.defaultFocusField != null )
			{
				control = this.getFieldByName( this.defaultFocusField ) as UIComponent;
			}
			else
			{
				control = this.getControlByIndex() as UIComponent;
			}

			if( control != null )
				this.callLater( control.setFocus );
			//( control.setFocus as Function ).apply();

		}

		public function cancel():void
		{
			this.dispatchEvent( new FormEvent( FormEvent.CANCEL, this ));
		}


		[Inspectable( enumeration="input,search",defaultValue="input" )]
		public var mode:String = FormModes.INPUT;

		private var _dataProvider:Object;

		public function get dataProvider():Object
		{
			return this._dataProvider;
		}

		public function set dataProvider( value:Object ):void
		{
			this._dataProvider = value;
			this.setData( value );
		}


		public var validators:Array = [];


		public function isValid():Boolean
		{
			var events:Array = [];
			for each( var validator:Validator in this.validators )
			{
				events.push( validator.validate());
			}

			for each( var event:ValidationResultEvent in events )
			{
				if( event.type == ValidationResultEvent.INVALID )
					return false;
			}

			return true;

		}

		public var submitEventType:String;


		public function submit():void
		{
			if( this.isValid())
			{
				if( submitEventType != null )
				{
					dispatchEvent( new FormEvent( submitEventType, this ));
				}
				else
				{
					dispatchEvent( new FormEvent( FormEvent.SUBMIT, this ));
				}
			}
		}


		public function cache():void
		{

		}

		public function getCacheValue( name:String ):*
		{
			return "";
		}




		public function getHiddenValues():Object
		{
			var data:Object = {};

			for each( var property:String in this.hiddenValues )
			{
				data[ property ] = this.getValueByName( property );
			}

			return data;
		}

		public function getValueByName( name:String ):*
		{

			for( var key:String in this.hiddenValues )
			{
				if( key == name )
					return this.hiddenValues[ key ];
			}


			for each( var control:IFormControl in this.getControls())
			{
				if( control.cName == name )
					return control.cValue;
			}

			return "";
		}


		public function getFieldByName( name:String ):*
		{
			for each( var control:IFormControl in this.getControls())
			{
				if( control.cName == name )
					return control;
			}

			return;
		}

		public function getControlByIndex( index:int = 0 ):IControl
		{
			var controls:Array = this.getControls();

			return controls[ index ] as IControl;
		}


		[ArrayElementType( "com.smashedapples.forms.IFormControl" )]
		private var _controls:Array = [];

		public function getControls():Array
		{
			_controls = [];
			getControlsImpl( this.getChildren());
			return _controls;
		}

		private function getControlsImpl( children:Array ):void
		{
			for( var child:String in children )
			{
				if( children[ child ] is IFormControl && children[ child ] != null )
				{
					_controls.push( children[ child ]);
				}
				else if( children[ child ] is Container )
				{
					getControlsImpl(( children[ child ] as Container ).getChildren());
				}
			}
		}



		public function getDataByList( list:String ):Object
		{
			return ObjectUtils.parseByName( this.getData(), list );
		}



		public function getData():Object
		{
			var data:Object = getHiddenData();

			for each( var control:IFormControl in this.getControls())
			{
				if( control.cInclude == false )
					continue;

				if( this.mode == FormModes.SEARCH )
				{
					if( control.cValue == "" )
						continue;

					if( control.cValue == null )
						continue;
				}
				data[ control.cName ] = control.cValue;
			}


			return data;
		}

		public function getHiddenData():Object
		{
			var data:Object = {};

			if( this.hidden.length == 0 )
				return data;

			for each( var key:String in hiddenValuesList())
			{
				if( hiddenValues.hasOwnProperty( key ))
				{
					data[ key ] = hiddenValues[ key ];
				}
				else
				{
					data[ key ] = null;
				}
			}
			return data;
		}

		public function setHiddenData( data:Object ):void
		{
			this.hiddenValues = {};

			for each( var hiddenKey:String in hiddenValuesList())
			{
				if( data.hasOwnProperty( hiddenKey ))
					this.hiddenValues[ hiddenKey ] = data[ hiddenKey ];
			}
		}

		public function reset():void
		{
			this.hiddenValues = [];
			for each( var control:IFormControl in this.getControls())
			{
				control.cReset()
			}

			dispatchEvent( new FormEvent( FormEvent.RESET, this ));
		}


		public function hiddenValuesList():Array
		{
			return this.hidden.split( "," );
		}

		public function setData( data:Object ):void
		{
			if( data == null )
				return;

			this.setHiddenData( data );

			for each( var control:IFormControl in this.getControls())
			{
				if( data.hasOwnProperty( control.cName ))
					control.cValue = data[ control.cName ];
			}
		}






	}
}